﻿--------------
--  Locals  --
--------------
local mod	= FAM:NewMod("TheStoneGuard", 1, 44, nil, nil, nil)

--------------
--  Events  --
--------------

function mod:OnInitialize()
    -- Called when the addon is loaded
end













--------------------------------------------------------------------------------
-- Declaration
--------------------------------------------------------------------------------

local addonName, vars = ...
local L = LibStub("AceLocale-3.0"):GetLocale(addonName)
StoneGuardAnnounce = LibStub("AceAddon-3.0"):NewAddon(addonName, "AceTimer-3.0")
local addon = StoneGuardAnnounce
local minimapIcon = LibStub("LibDBIcon-1.0")
local LDB, LDBo

vars.svnRev = {}
vars.svnRev["StoneGuardAnnounce.lua"] = tonumber(("$Revision: 1 $"):match("%d+"))

vars.defaults = {
	profile = {
		logLevel = 2,
		minimap = {
			hide = false,
		},
		loaded = false,
		enable = true,
		enableLfr = false,
		enableNormal = true,
		enableHeroic = true,
		raidWarning = true,
		whisper = true,
		self = true,
		pullConfiguration = true,
		raid = {
			composition = {
				TANK = {},
				HEALER = {},
				DAMAGER = {},
			},
		},
		guardians = {
			cobalt = { id = 60051, name = L["Cobalt Guardian"], isPullBackup = false },
			jade = { id = 60043, name = L["Jade Guardian"], isPullBackup = true },
			jasper = { id = 59915, name = L["Jasper Guardian"], isPullBackup = false },
			amethyst = { id = 60047, name = L["Amethyst Guardian"], isPullBackup = false },
		},
	}
}
vars.spellIds = {
	trueForm			  = 115791, -- True Form
	solidStone            = 115745, -- Solid Stone
	cobaltOverload        = 115840, -- Cobalt Overload
	cobaltPetrification   = 115852, -- Cobalt Petrification
	cobaltTrueForm        = 115771, -- Cobalt True Form
	amethystOverload      = 115844, -- Amethyst Overload
	amethystPetrification = 116057, -- Amethyst Petrification
	amethystTrueForm      = 115829, -- Amethyst True Form
	jadeOverload          = 115842, -- Jade Overload
	jadePetrification     = 116006, -- Jade Petrification
	jadeTrueForm          = 115827, -- Jade True Form
	jasperOverload        = 115843, -- Jasper Overload
	jasperPetrification   = 116036, -- Jasper Petrification
	jasperTrueForm        = 115828, -- Jasper True Form
}
vars.events = {
	general = {
		GROUP_ROSTER_UPDATE = "OnRaidCompositionUpdate",
		PARTY_LEADER_CHANGED = "OnRaidLeaderChanged",
		PLAYER_DIFFICULTY_CHANGED = "Update",
		ZONE_CHANGED = "Update",
		ZONE_CHANGED_INDOORS = "Update",
		ZONE_CHANGED_NEW_AREA = "Update",
		CHAT_MSG_ADDON = "CHAT_MSG_ADDON",
	},
	beforeFight = {
		INSTANCE_ENCOUNTER_ENGAGE_UNIT = "OnUnitEngaged",
	},
	duringFight = {
		SPELL_CAST_SUCCESS = "OnSpellCastSuccess",
		UNIT_SPELLCAST_SUCCEEDED = "OnUnitSpellCastSucceeded",
		UNIT_POWER = "OnUnitPowerChanged",
	},
}

local settings = vars.defaults.profile
local optionsFrame
StaticPopupDialogs["STONEGUARDANNOUNCE_ROLEPOLL"] = {
	preferredIndex = 3, -- reduce the chance of UI taint
	text = string.format(L["%s requires raid members to have roles assigned. Would you like to run a Role Check now?"], addonName),
	button1 = YES,
	button2 = NO,
	OnAccept = function () InitiateRolePoll() end,
	timeout = 0,
	whileDead = true,
	hideOnEscape = true,
	showAlert = true,
	enterClicksFirstButton = true,
}

--------------------------------------------------------------------------------
-- Local functions
--------------------------------------------------------------------------------

-- Clone a table
local function cloneTable(t)
	if not t then
		return nil
	elseif type(t) == "table" then
		local res = {}
		for k,v in pairs(t) do
			res[cloneTable(k)] = cloneTable(v)
		end
		return res
	else
		return t
	end
end

-- Add a message on the chat
local function addMessage(msg)
	DEFAULT_CHAT_FRAME:AddMessage("|cff00ffff"..addonName.."|r : "..msg)
end

-- Add a message on the chat if the log level is greater or equal to the required verbosity
local function log(msg, color, verbosity)
	if settings.logLevel >= verbosity then addMessage("|"..color..msg.."|r") end
end

-- Add a message on the chat with warn verbosity
local function warn(msg)
	log("Warn - "..msg, "cffff6060", 1)
end
-- Add a message on the chat with information verbosity
local function info(msg)
	log("Info - "..msg, "cff00ccff", 2)
end

-- Add a message on the chat with debug verbosity
local function debug(msg)
	log("Debug - "..msg, "cff8B8B83", 3)
end

-- Get the unit name of a given unit
local function unitToName(unit)
  return GetUnitName(unit, false)
end

-- Indicate wether a given unit has a given buff
local function hasBuff(unitName, buffName)
	return UnitBuff(unitName, buffName) ~= nil
end

local function wspFilter(self, event, msg, author, ...) -- la refaire
   --if msg and msg:find(L["Run to the totem!!!"]) then return true end
end

--------------------------------------------------------------------------------
-- Events
--------------------------------------------------------------------------------

-- Fires when the addon is initialized
function addon:OnInitialize()
	addon:SetupVersion()
	addon.db = LibStub("AceDB-3.0"):New("StoneGuardAnnounceDB", vars.defaults)
	addon:RefreshConfiguration()
	debug("OnInitialize")
	addon:BuildOptions()
	LibStub("AceEvent-3.0"):Embed(addon)
	LibStub("AceConfigRegistry-3.0"):ValidateOptionsTable(addon.options, addonName)
	LibStub("AceConfig-3.0"):RegisterOptionsTable(addonName, addon.options, {"stoneguardannounce", "sga"})
	optionsFrame = LibStub("AceConfigDialog-3.0"):AddToBlizOptions(addonName, addonName, nil, "general")
	optionsFrame.default = function()
       for k,v in pairs(vars.defaults.profile) do settings[k] = table_clone(v) end
		addon:RefreshConfiguration()
		if InterfaceOptionsFrame:IsShown() then
			InterfaceOptionsFrame:Hide()
			addon:ToggleOptionsFrame()
		end
	end
	addon.options.args.profiles = LibStub("AceDBOptions-3.0"):GetOptionsTable(addon.db)
	LibStub("AceConfigDialog-3.0"):AddToBlizOptions(addonName, L["Profiles"], addonName, "profiles")

	self.db.RegisterCallback(self, "OnProfileChanged", "RefreshConfiguration")
	self.db.RegisterCallback(self, "OnProfileCopied", "RefreshConfiguration")
	self.db.RegisterCallback(self, "OnProfileReset", "RefreshConfiguration")
	self.db.RegisterCallback(self, "OnDatabaseReset", "RefreshConfiguration")
	addon:InitializeSpellNames()
	addon.inFight = false
	addon.initialized = true
end

-- Fires when the addon is enabled
function addon:OnEnable()
	debug("OnEnable")
	addon:RegisterEvents(vars.events.general)
	RegisterAddonMessagePrefix(addonName)
	RegisterAddonMessagePrefix("D4") -- snoop DBM messages
	ChatFrame_AddMessageEventFilter("CHAT_MSG_WHISPER_INFORM", wspFilter)

	if LDB then return end
	if AceLibrary and AceLibrary:HasInstance("LibDataBroker-1.1") then
		LDB = AceLibrary("LibDataBroker-1.1")
	elseif LibStub then
		LDB = LibStub:GetLibrary("LibDataBroker-1.1", true)
	end
	if LDB then
		LDBo = LDB:NewDataObject(addonName, {
			type = "launcher",
			label = addonName,
			icon = "Interface\\Icons\\inv_misc_reforgedarchstone_01",
			OnClick = function(self, button)
				if button == "RightButton" then
					addon:ToggleOptionsFrame()
				else
					settings.enable = not settings.enable 
					addon:RefreshConfiguration()
				end
			end,
			OnTooltipShow = function(tooltip)
				if tooltip and tooltip.AddLine then
					tooltip:SetText(addonName)
                    tooltip:AddLine("|cffff8040"..L["Left Click"].."|r "..L["to deactivate"])
					tooltip:AddLine("|cffff8040"..L["Right Click"].."|r "..L["for options"])
					tooltip:Show()
				end
			end,
		})
	end 

	if LDBo then minimapIcon:Register(addonName, LDBo, settings.minimap) end
	addon:Refresh()
end

-- Fires when the addon is disabled
function addon:OnDisable()
	debug("OnDisable")
	addon:UnregisterEvents(vars.events.general)
end

-- Raised when the raid composition was updated
function addon:OnRaidCompositionUpdate()
	debug("OnRaidCompositionUpdate")
	-- Update the raid composition only if the addon is enabled
	if settings.enable then addon:LoadRaidComposition() end
	addon:Update()
end

-- Raised when the raid leader has changed
function addon:OnRaidLeaderChanged()
	debug("OnRaidLeaderChanged")
	-- Update the raid composition only if the addon is enabled
	if settings.enable then addon:UpdateRaidComposition() end
	addon:Update()
end

-- Fires when a boss has been engaged in an instance
function addon:OnUnitEngaged()
	debug("OnUnitEngaged")
	-- update the engaged guardians counter
	if not addon.inFight then
		addon.engagedGuardians = 1
	else
		addon.engagedGuardians = addon.engagedGuardians + 1
	end
	-- only update the inFight status once
	if addon:AntiSpam(-1) then
		addon.inFight = (UnitExists("boss1") or UnitExists("boss2")) and not addon.inFight
		addon.pull = addon.inFight
		if addon.inFight then
			addon:RegisterEvents(vars.events.duringFight)
		else
			addon:UnregisterEvents(vars.events.duringFight)
		end
	end
	-- only scan the active guardians when all of them have been engaged
	if addon.engagedGuardians == addon.raid.bosses then addon:ScanActiveGuardians() end
end

-- Fires when a unit's power level changes
function addon:OnUnitPowerChanged(eventName, unitID, powerType)
	debug("OnUnitPowerChanged")
	-------------
	-- unitID : boss1 ou boss2 ou boss3 ou boss4
	-- powerType : ENERGY
	-------------
	-- only react when boss power changed
	if string.find(unitID, "boss[1234]") then
		local unitPower = UnitPower(unitID, powerType)
		local guardian = addon.guardians[unitID]
		addon.guardians[unitID].power = unitPower
		-- if the current guardian is the active guardian
		if addon.activeGuardian ~= nil and addon.activeGuardian.bossName == unitID then
			info(string.format(addon.guardians[unitID].guardianName.." est a %d de puissance !!!", unitPower))
			-- if we are in the pull phase and the guardian power is greater or equal to 45
			if addon.pull and unitPower >= 5 then--45
				warn("ARG : PULL NORMAL")
				addon.pull = false
				local anotherTank
				for playerName, playerInfos in pairs(addon.raid.composition["TANK"]) do
					if playerName ~= addon.activeGuardian.tank then
						anotherTank = playerName
						break
					end
				end
				addon.activeGuardian.tank = anotherTank
				local msg = "taunt le "..tostring(addon.activeGuardian.displayName).." !!"
				if settings.whisper then SendChatMessage(msg, "WHISPER", nil, anotherTank) end
				msg = anotherTank.." doit "..msg
				if settings.raidWarning then SendChatMessage(msg, "RAID_WARNING") end
				if settings.self then warn(msg) end
			end
		end
	end
end

function addon:HandlePetrifications(spellID)
	-- cobalt petrification
	if spellID == vars.spellIds.cobaltPetrification and addon:AntiSpam(1) then
		addon.activeGuardian = addon.guardians[settings.guardians.cobalt.bossName]
		return true
	-- jade petrification
	elseif spellID == vars.spellIds.jadePetrification and addon:AntiSpam(2) then
		addon.activeGuardian = addon.guardians[settings.guardians.jade.bossName]
		return true
	-- jasper petrification
	elseif spellID == vars.spellIds.jasperPetrification and addon:AntiSpam(3) then
		addon.activeGuardian = addon.guardians[settings.guardians.jasper.bossName]
		return true
	-- amethyst petrification
	elseif spellID == vars.spellIds.amethystPetrification and addon:AntiSpam(4) then
		addon.activeGuardian = addon.guardians[settings.guardians.amethyst.bossName]
		return true
	end
	return false
end

-- Fires when a unit's spell cast succeeds
function addon:OnUnitSpellCastSucceeded(eventName, unitID, spellName, spellRank, lineID, spellID)
	debug("OnUnitSpellCastSucceeded")
	-------------
	-- unitID : boss1 ou boss2 ou boss3 ou boss4
	-- spellName : Forme véritable /!\ nom traduit /!\
	-- spellRank : nil
	-- lineID : 0 pour les boss
	-- spellID : voir vars.spellIds
	-------------
	-- a petrification just occured
	if addon:HandlePetrifications(spellID) then
		debug("activeGuardian - bossName : "..addon.activeGuardian.bossName)
		-- the active guardian is in solid stone state : its tank must quickly taunt another guardian
		if hasBuff(addon.activeGuardian.bossName, addon.spellNames.solidStone) then
			local targetGuardian
			if addon.pull then
				warn("ARG : PULL FOIREUX")
				targetGuardian = addon.pullBackupGuardian
				addon.pull = false
			else
				warn("ARG : ECHANGE NORMAL")
				local lowestPower = 100
				for guardianName, guardianInfos in pairs(addon.guardians) do
					local guardian = addon.guardians[guardianName]
					if not guardian.power then
						targetGuardian = guardian
						break
					elseif guardian.power < lowestPower then
						lowestPower = guardian.power
						targetGuardian = guardian
					end
				end
			end
			targetGuardian.tank = addon.activeGuardian.tank
			msg = "taunt "..tostring(targetGuardian.displayName).." !!"
			if settings.whisper then SendChatMessage(msg, "WHISPER", nil, targetGuardian.tank) end
			msg = targetGuardian.tank.." doit "..msg
			if settings.raidWarning then SendChatMessage(msg, "RAID_WARNING") end
			if settings.self then warn(msg) end
		end
	end
end

-- Fires when channeled spells begin or when instant cast spells are cast
function addon:OnSpellCastSuccess(args)
	debug("OnSpellCastSuccess")
	-- check if the addon is enabled
	if args:IsSpellID(115840) then -- Cobalt
		info("Cobalt")
	elseif args:IsSpellID(115842) then -- Jade
		info("Jade")
	elseif args:IsSpellID(115843) then -- Jasper
		info("Jasper")
	elseif args:IsSpellID(115844) then -- Amethyst
		info("Amethyst")
	end
end

--------------------------------------------------------------------------------
-- Functions
--------------------------------------------------------------------------------

-- Set the addon version
function addon:SetupVersion()
	-- get the metadata revision
	local svnRev = 0
	local files = vars.svnRev
	files["X-Build"] = tonumber((GetAddOnMetadata(addonName, "X-Build") or ""):match("%d+"))
	files["X-Revision"] = tonumber((GetAddOnMetadata(addonName, "X-Revision") or ""):match("%d+"))
	-- Compare the core revision and the metadata revision
	for _,v in pairs(files) do
		if v and v > svnRev then svnRev = v end
	end
	-- set the revision
	addon.revision = svnRev

	-- get the metadata version
	files["X-Curse-Packaged-Version"] = GetAddOnMetadata(addonName, "X-Curse-Packaged-Version")
	files["Version"] = GetAddOnMetadata(addonName, "Version")
	-- set the version
	addon.version = files["X-Curse-Packaged-Version"] or files["Version"] or "@"
	if string.find(addon.version, "@") then addon.version = "r"..svnRev end
end

-- Refresh the configuration
function addon:RefreshConfiguration()
	-- load the settings from the db
	settings = addon.db.profile
	addon.settings = settings
	debug("RefreshConfiguration")
	-- use the default settings when settings are not found
	for k,v in pairs(vars.defaults.profile) do
		if settings[k] == nil then settings[k] = cloneTable(v) end
	end
	addon.raid = settings.raid
	settings.loaded = true
	addon:Refresh()
end

-- Refresh when the settings have changed
function addon:Refresh()
	debug("Refresh")
	if not addon.initialized then return end
	-- hide the minimap icon if necessary
	if LDBo then
		if settings.minimap.hide then
			minimapIcon:Hide(addonName)
		else
			minimapIcon:Show(addonName)
		end
	end
	addon:Update()
end

-- Enable or disable the addon if necessary
function addon:Update()
	debug("Update")
	-- check if the addon is initialized
	if not addon.initialized then return end
	local isInZone = addon:IsInZone()
	-- addon is enabled
	if addon.enabled then
		-- player is in zone and should make annoucements
		if isInZone and addon:ShouldAnnounce() then return end
		-- addon must be disabled
		addon.enabled = false
		addMessage(L["Addon disabled."])
		addon:UnregisterEvents(vars.events.beforeFight)
	-- addon is disabled but player is in zone
	elseif isInZone then
		-- player should make annoucements
		if addon:ShouldAnnounce() then
			addon.enabled = true
			addon.warning = false
			addon:LoadRaidComposition()
			addMessage(L["Version"].." "..addon.version)
			addMessage(L["Addon enabled. Type '/sga config' for options."])
			addon:RegisterEvents(vars.events.beforeFight)
			if addon.raid.missingRoles and addon.raid.missingRoles > 0 then StaticPopup_Show("STONEGUARDANNOUNCE_ROLEPOLL") end
		-- player can't make announcements and have not been warned yet
		elseif not addon:CanAnnounce() and not addon.warning then
			addMessage(L["You must have raid lead or assist to make annoucements."])
			addon.warning = true
		end
	end
end

-- Register events of a given category
-- @param events table containing the mapping between an event name and its implementation function name
function addon:RegisterEvents(events)
	for eventName, functionName in pairs(events) do 
		addon:RegisterEvent(eventName, functionName)
	end
end

-- Unregister events of a given category
-- @param events table containing the events names
function addon:UnregisterEvents(events)
	for eventName, _ in pairs(events) do 
		addon:UnregisterEvent(eventName)
	end
end

-- Check if the player is in the Stone Guard zone
function addon:IsInZone()
	debug("IsInZone")
	-- save current map settings
	local oldMap = GetCurrentMapAreaID()
	local oldLvl = GetCurrentMapDungeonLevel()
	-- force to right zone
	SetMapToCurrentZone()
	-- get the real map and position settings
	local map = GetCurrentMapAreaID()
	local lvl = GetCurrentMapDungeonLevel()
	local unitX, unitY = GetPlayerMapPosition("player")
	-- restore saved map settings
	SetMapByID(oldMap)
	if oldLvl and oldLvl > 0 then SetDungeonMapLevel(oldLvl) end
	-- check the actual position
	if not unitX then unitX, unitY = 0,0 end
	unitX, unitY = unitX*100, unitY*100
	return (map == 896 and lvl == 1 and unitX > 45)
end

-- Check if the difficulty is enabled
function addon:IsEnabledDifficulty()
	debug("IsEnabledDifficulty")
	-- check if the addon is enabled
	if not settings.enable then return false end
	-- update the difficulty
	addon:UpdateDifficulty()
	-- return the setting related to current difficulty
	if addon.raid.difficulty == "LFR" then
		return settings.enableLfr
	elseif addon.raid.difficulty == "heroic" then
		return settings.enableHeroic
	else
		return settings.enableNormal
	end
end

-- Update the current difficulty
function addon:UpdateDifficulty()
	debug("UpdateDifficulty")
	-- get the raid informations
	local instanceName, instanceType, difficulty, difficultyName, maxPlayers, playerDifficulty, isDynamicInstance = GetInstanceInfo()
	-- set the raid size
	if maxPlayers ~= 10 and maxPlayers ~= 25 then maxPlayers = 25 end
	addon.raid.size = maxPlayers
	-- set the raid bosses
	addon.raid.bosses = 3
	if maxPlayers == 25 then
		addon.raid.bosses = 4
	else
		addon.raid.bosses = 3
	end
	-- set the raid difficulty
	if HasLFGRestrictions() then
		addon.raid.difficulty = "LFR"
	elseif difficulty == 3 or difficulty == 4 then
		addon.raid.difficulty = "heroic"
	else
		addon.raid.difficulty = "normal"
	end
end

-- Check if the player can announce
function addon:CanAnnounce()
	debug("CanAnnounce")
	return UnitIsGroupLeader("player") or UnitIsGroupAssistant("player")
end

-- Check if the player should announce
function addon:ShouldAnnounce()
	debug("ShouldAnnounce")
	return addon:CanAnnounce() and (addon:IsEnabledDifficulty() or addon.dryRun or settings.logLevel > 0)
end

-- Initialize the spell names
function addon:InitializeSpellNames()
	debug("InitializeSpellNames")
	if not addon.spellNames then addon.spellNames = {} end
	for key, id in pairs(vars.spellIds) do
		if not addon.spellNames[key] then addon.spellNames[key] = GetSpellInfo(id) end
	end
end

-- Toggle the options frame
function addon:ToggleOptionsFrame()
	debug("ToggleOptionsFrame")
	if optionsFrame then
		-- if the options frame is shown
		if (InterfaceOptionsFrame:IsShown()) then
			InterfaceOptionsFrame:Hide()
		-- if the options frame is hidden
		else
			-- update the raid composition
			addon:UpdateRaidComposition()
			InterfaceOptionsFrame_OpenToCategory(optionsFrame)
		end
	end
end

-- Cleanup the raid composition
function addon:CleanUpRaidComposition()
	debug("UpdateRaidComposition")
	-- cleanup each raid role
	for _, roleInfos in pairs(addon.raid.composition) do
		--cleanup each player infos
		for _,playerInfos in pairs(roleInfos) do
			playerInfos.unitId = nil
		end
	end
end

-- Update the raid composition
function addon:UpdateRaidComposition()
	debug("UpdateRaidComposition")
	-- check if the addon is enabled
	if not settings.enable then return end
	-- cleanup the raid composition
	addon:CleanUpRaidComposition()
	local units = 0
	addon.raid.missingRoles = 0
	-- scan the 40 raid slots
	for i=1, 40 do
		local unit = "raid"..i
		-- if a player is in this raid slot
		if UnitExists(unit) then
			units = units + 1
			local playerName = unitToName(unit)
			local playerRole = UnitGroupRolesAssigned(unit)
			if playerRole == "NONE" then
				addon.raid.missingRoles = addon.raid.missingRoles + 1
			else
				addon.raid.composition[playerRole][playerName] = {
					unitId = unit,
					name = playerName,
				}
			end
		end
	end
	if addon.raid.missingRoles > 0 then addMessage(string.format(L["WARNING: %d players do not have roles assigned and will be ignored."], addon.raid.missingRoles)) end
	info("Processed "..units.." players, "..addon.raid.missingRoles.." unassigned roles")
end

-- Load the raid composition
function addon:LoadRaidComposition()
	debug("LoadRaidComposition")
	addon:UpdateRaidComposition()
	-- cleanup previous players info
	for unitRole, roleInfos in pairs(addon.raid.composition) do
		for playerName, playerInfos in pairs(roleInfos) do
			if not playerInfos.unitId and (not playerInfos.text or #playerInfos.text == 0) then
				info("Cleaning old player : "..playerName)
				addon.raid.composition[unitRole][playerName] = nil
			end
		end
	end
end

-- An anti spam function to throttle spammy events (e.g. SPELL_AURA_APPLIED on all group members)
-- @param eventId the id to distinguish different events
-- @param time the time to wait between two events (optional, default 2.5 seconds)
function addon:AntiSpam(eventId, time)
	debug("AntiSpam")
	if GetTime() - (addon["lastAntiSpam" .. tostring(eventId)] or 0) > (time or 2.5) then
		addon["lastAntiSpam" .. tostring(eventId)] = GetTime()
		return true
	else
		return false
	end
end

-- Scan the active guardians
function addon:ScanActiveGuardians()
	debug("ScanActiveGuardians")
	addon.guardians = {}
	-- scan the 4 possible guardians
	for i = 1, 4 do
		local name = "boss"..i
		local guid = UnitGUID(name)
		-- if this guardian exists
		if guid then
			local bossId = tonumber(guid:sub(6, 10), 16)
			-- search it in the settings
			for guardianName, guardianInfos in pairs(settings.guardians) do
				-- if found, update the guardians informations with the settings informations and stop the research
				if guardianInfos.id == bossId then
					addon.guardians[name] = {
						id = bossId,
						bossName = name,
						guardianName = guardianName,
						displayName = guardianInfos.name,
						tank = guardianInfos.tank
					}
					guardianInfos.bossName = name
					if guardianInfos.isPullBackup then addon.pullBackupGuardian = addon.guardians[name] end
					break
				end
			end
		end
	end
end

-- Builds the options menu
function addon:BuildOptions()
	debug("BuildOptions")
	addon.options = {
		type = "group",
		set = function(info, value)
			local s = settings ; for i = 2,#info-1 do s = s[info[i]] end
			s[info[#info]] = value; info(info[#info].." set to: "..tostring(value))
			addon:Refresh()
		end,
		get = function(info)
			local s = settings ; for i = 2,#info-1 do s = s[info[i]] end
			return s[info[#info]]
		end,
		args = {
			general = {
				type = "group",
				inline = true,
				name = L["General"],
				args = {
					-- label : addon version
					version = {
						order = 1,
						type = "description",
						fontSize = "medium",
						name = L["Version"].." "..addon.version.."\n",
					},
					--------------------------------------------------------------------------------------------------
					-- checkbox : enable/disable minimap icon
					minimap = {
						order = 11,
						name = L["Minimap Icon"],
						desc = L["Display minimap icon"],
						type = "toggle",
						set = function(info, value)
							settings.minimap.hide = not value
							addon:Refresh()
						end,
						get = function()
							return not settings.minimap.hide
						end,
					},
					-- checkbox : enable/disable addon
					enable = {
						order = 12,
						name = L["Enable"],
						desc = L["Enable the addon"],
						type = "toggle",
					},
					-- checkbox : enable/disable LFR mode
					enableLfr = {
						order = 13,
						name = L["LFR"],
						desc = L["Enable the addon in Looking For Raid difficulty"],
						type = "toggle",
						disabled = function()
							return not settings.enable
						end,
					},
					-- checkbox : enable/disable normal mode
					enableNormal = {
						order = 14,
						name = L["Normal"],
						desc = L["Enable the addon in Normal difficulty"],
						type = "toggle",
						disabled = function()
							return not settings.enable
						end,
					},
					-- checkbox : enable/disable heroic mode
					enableHeroic = {
						order = 15,
						name = L["Heroic"],
						desc = L["Enable the addon in Heroic difficulty"],
						type = "toggle",
						disabled = function()
							return not settings.enable
						end,
					},
					-- dropdownlist : log level
					logLevel = {
						order = 16,
						name = L["Log level"],
						desc = L["Maximum log level"],
						type = "select",
						values = { [0] = L["None"], [1] = L["Warning"], [2] = L["Information"], [3] = L["Debug"] },
						set = function(info, value)
							settings.logLevel = value
							addon:Refresh()
						end,
					    get = function(info)
							return settings.logLevel
						end,
					},
					--------------------------------------------------------------------------------------------------
					-- header : announcement options
					announcementHeader = {
						order = 21,
						name = L["Announcement Options"],
						type = "header",
						cmdHidden = true,
					},
					-- label : raid lead/assist needed
					announceWarn = {
						order = 31,
						type = "description",
						fontSize = "medium",
						name = function() 
							if addon:CanAnnounce() then
								return ""
							else
								return "\124cffff0000".. L["You must have raid lead or assist to make annoucements."].."\124r"
							end
						end,
					},
					-- checkbox : raid announces
					raidWarning = {
						order = 41,
						name = L["Raid Warning"],
						desc = L["Send a raid warning announcing the tank who must taunt a given Guardian"],
						type = "toggle",
						disabled = function()
							return not settings.enable
						end,
					},
					-- checkbox : whisper announces
					whisper = {
						order = 42,
						name = L["Whisper"],
						desc = L["Whisper announces to players"],
						type = "toggle",
						disabled = function()
							return not settings.enable
						end,
					},
					-- checkbox : self announces
					self = {
						order = 43,
						name = L["Self"],
						desc = L["Output to self players announces"],
						type = "toggle",
						disabled = function()
							return not settings.enable
						end,
					},
					--------------------------------------------------------------------------------------------------
					-- header : raid configuration
					raidHeader = {
						order = 51,
						name = L["Raid configuration"],
						type = "header",
						cmdHidden = true,
					},
					-- button : role check
					roleCheck = {
						order = 61,
						name = L["Role Check"],
						desc = L["Start a Role Check"],
						type = "execute",
						disabled = function()
							return not addon:CanAnnounce()
						end,
						func = function()
							InitiateRolePoll()
						end,
					},
					-- button : refresh settings
					refresh = {
						order = 62,
						name = L["Refresh"],
						desc = L["Refresh this display"],
						type = "execute",
						func = function()
							addon:RefreshConfigPanel()
						end,
						cmdHidden = true,
					},
					-- button : reset settings
					reset = {-- ffa : on garde?
						order = 63,
						name = L["Reset"],
						desc = L["Reset player settings"],
						type = "execute",
						func = function()
							addon:LoadRaidComposition()
							addon:RefreshConfigPanel()
						end,
					},
					-- label : missing roles warning
					roleCheckWarn = {
						order = 71,
						type = "description",
						fontSize = "medium",
						name = function() 
							if addon.raid.missingRoles and addon.raid.missingRoles > 0 then 
								return string.format("\124cffff0000"..L["WARNING: %d players do not have roles assigned and will be ignored."].."\124r",addon.raid.missingRoles)
							else
								return ""
							end
						end,
					},
					--------------------------------------------------------------------------------------------------
					-- panel : pull configuration
					pull = {
						order = 81,
						type = "group",
						name = function()
							addon.options.args.general.args.pull.args = addon:pullCustomization()
							return L["Pull"] 
						end,
						args = {},
					},
				},
			},
		},
	} 
end
 
-- Get the pull customization panel
function addon:pullCustomization()
	debug("pullCustomization")
	local ret = {}
	-- checkbox : enable/disable
	ret.enable = {
		order = 1001,
		name = L["Enable"],
		desc = L["Enable pull customization"],
		type = "toggle",
		width = "full",
		set = function(info, value)
			settings.pullConfiguration = value
			addon:Update()
		end,
		get = function(info)
			return settings.pullConfiguration
		end,
	}
	local nextOrder = 1011
	for guardianName, guardianInfos in pairs(settings.guardians) do
		-- list item : guardian name
		ret[guardianName] = {
			order = nextOrder,
			type = "group",
			name = guardianInfos.name,
			args = {
				-- dropdownlist : tank selection
				tank = {
					order = 10001,
					name = L["Tank"].." : ",
					type = "select",
					values = {},
					set = function(info, value)
						guardianInfos.tank = value
						addon:Update()
					end,
					get = function(info)
						return guardianInfos.tank
					end,
				},
				-- checkbox : is the pull backup guardian
				isPullBackup = {
					order = 10011,
					name = L["Is pull backup"],
					desc = L["Indicate wether this Guardian must be pulled when the first petrification occurs on an alone Guardian"],
					type = "toggle",
					disabled = function()
						return guardianInfos.tank == nil
					end,
					set = function(info, value)
						guardianInfos.isPullBackup = value
						addon:Update()
					end,
					get = function(info)
						return guardianInfos.isPullBackup
					end,
				},
			},
		}
		local tanks = 1
		for playerName, playerInfos in pairs(addon.raid.composition["TANK"]) do
			ret[guardianName].args.tank.values[playerName] = playerName
			tanks = tanks + 1
		end
		nextOrder = nextOrder + 1
	end
	return ret
end

function addon:RefreshConfigPanel()
  addon:UpdateRaidComposition()
  if optionsFrame then
    if ( InterfaceOptionsFrame:IsShown() ) then
      InterfaceOptionsFrame:Hide();
      InterfaceOptionsFrame_OpenToCategory(optionsFrame)
    end
  end
end